Ext.define('AmpleHarvest.objects.toolbar.cSearch',
{
	extend				: 'Ext.util.Observable',
	alias				: 'widget.ampleharvest-objects-toolbar-csearch',
	requires			:
	[
			'Ext.menu.CheckItem', 'Ext.toolbar.Toolbar',
			'Ext.form.field.Trigger', 'Ext.util.KeyMap', 'Ext.menu.Menu'
	],
	uses				: [],
	searchText			: 'Search',
	searchTipText		: 'Type a text to search and press Enter',
	selectAllText		: 'Select All',
	position			: 'bottom',
	iconCls				: 'icon-magnifier',
	checkIndexes		: 'all',
	disableIndexes		: [],
	dateFormat			: undefined,
	showSelectAll		: true,
	menuStyle			: 'checkbox',
	minCharsTipText		: 'Type at least {0} characters',
	mode				: 'remote',
	width				: 300,
	xtype				: 'gridsearch',
	paramNames			:
	{
		fields	: 'fields',
		query	: 'query'
	},
	shortcutKey			: 'r',
	shortcutModifier	: 'alt',

	init				: function(obj_Grid)
	{
		this.m_obj_Grid = obj_Grid;

		// setup toolbar container if id was given
		if ('string' === typeof this.toolbarContainer)
		{
			this.toolbarContainer = Ext.getCmp(this.toolbarContainer);
		}

		// do our processing after grid render and reconfigure

		obj_Grid.onRender = Ext.Function.createSequence(obj_Grid.onRender,
				this.onRender, this
		);
		obj_Grid.reconfigure = Ext.Function.createSequence(
				obj_Grid.reconfigure, this.reconfigure, this
		);
	},

	onRender			: function()
	{
		var obj_This = this;
		var m_obj_Panel = this.toolbarContainer || this.m_obj_Grid;
		var m_obj_TB = 'bottom' === this.position
				? m_obj_Panel.bbar
				: m_obj_Panel.tbar;

		if (!m_obj_TB)
		{
			m_obj_TB = Ext.create('Ext.toolbar.Toolbar',
					{
						dock	: this.position
					});

			m_obj_Panel.addDocked(m_obj_TB);
		}

		m_obj_TB.layout.pack = "end";

		// add menu
		this.menu = Ext.create('Ext.menu.Menu');

		// handle position
		if ('right' === this.align)
		{
			m_obj_TB.addFill();
		}
		else
		{
			if (0 < m_obj_TB.items.getCount())
			{
				m_obj_TB.addSeparator();
			}
		}

		// add menu button
		m_obj_TB.add(
				{
					text	: this.searchText,
					menu	: this.menu,
					iconCls	: this.iconCls
				});

		this.m_obj_Field = Ext.create('Ext.form.field.Trigger',
				{
					width			: this.width,
					triggerCls		: 'x-form-search-trigger',
					selectOnFocus	: undefined === this.selectOnFocus
							? true
							: this.selectOnFocus,
					minLength		: this.minLength,
					onTriggerClick	: Ext.Function.createBuffered(
							this.onTriggerSearch, 0, obj_This
					)
				});

		// install event handlers on input field
		this.m_obj_Field.on('render', function()
				{
					this.m_obj_Field.el.dom.qtip = this.minChars
							? String
									.format(this.minCharsTipText, this.minChars)
							: this.searchTipText;

					if (this.minChars)
					{
						this.m_obj_Field.el.on(
								{
									scope	: this,
									buffer	: 300,
									keyup	: this.onKeyUp
								});
					}

					// install key map
					var map = new Ext.util.KeyMap(this.m_obj_Field.el,
							[
									{
										key		: Ext.EventObject.ENTER,
										scope	: this,
										fn		: this.onTriggerSearch
									},
									{
										key		: Ext.EventObject.ESC,
										scope	: this,
										fn		: this.onTriggerClear
									}
							]);

					map.stopEvent = true;
				}, this,
				{
					single	: true
				}
		);

		m_obj_TB.add(this.m_obj_Field);

		// reconfigure
		this.reconfigure();

		// keyMap
		if (this.shortcutKey && this.shortcutModifier)
		{
			var shortcutEl = this.m_obj_Grid.getEl();
			var shortcutCfg =
			[
					{
						key			: this.shortcutKey,
						scope		: this,
						stopEvent	: true,
						fn			: function()
						{
							this.m_obj_Field.focus();
						}
					}
			];
			shortcutCfg[0][this.shortcutModifier] = true;
			this.keymap = new Ext.KeyMap(shortcutEl, shortcutCfg);
		}

		if (true === this.autoFocus)
		{
			this.m_obj_Grid.store.on(
					{
						scope	: this,
						load	: function()
						{
							this.m_obj_Field.focus();
						}
					});
		}
	},// eo function onRender

	onKeyUp				: function()
	{
		var length = this.m_obj_Field.getValue().toString().length;
		if (0 === length || this.minChars <= length)
		{
			this.onTriggerSearch();
		}
	} // eo function onKeyUp

	/**
	 * private Clear Trigger click handler
	 */
	,
	onTriggerClear		: function()
	{
		if (this.m_obj_Field.getValue())
		{
			this.m_obj_Field.setValue('');
			this.m_obj_Field.focus();
			this.onTriggerSearch();
		}
	} // eo function onTriggerClear
	/**
	 * private Search Trigger click handler (executes the search, local or
	 * remote)
	 */
	,
	onTriggerSearch		: function()
	{
		if (!this.m_obj_Field.isValid())
		{
			return;
		}
		var val = this.m_obj_Field.getValue();
		var store = this.m_obj_Grid.store;

		// grid's store filter
		if ('local' === this.mode)
		{
			store.clearFilter();
			if (val)
			{
				store.filterBy(function(r)
				{
					var retval = false;
					this.menu.items.each(function(item)
					{
						if (!item.checked || retval)
						{
							return;
						}
						var rv = r.get(item.dataIndex);
						rv = rv instanceof Date
								? rv
										.format(this.dateFormat
												|| r.fields.get(item.dataIndex).dateFormat)
								: rv;
						var re = new RegExp(val, 'gi');
						retval = re.test(rv);
					}, this
					);
					if (retval)
					{
						return true;
					}
					return retval;
				}, this
				);
			}
		}
		// ask server to filter records
		else
		{
			// clear start (necessary if we have paging)
			if (store.lastOptions && store.lastOptions.params)
			{
				store.lastOptions.params[store.paramNames.start] = 0;
			}

			// get fields to search array
			var fields = [];
			this.menu.items.each(function(item)
					{
						if (item.checked)
						{
							fields.push(item.dataIndex);
						}
					});

			// add fields and query to baseParams of store
			delete(store.proxy.extraParams[this.paramNames.fields]);
			delete(store.proxy.extraParams[this.paramNames.query]);
			if (store.lastOptions && store.lastOptions.params)
			{
				delete(store.lastOptions.params[this.paramNames.fields]);
				delete(store.lastOptions.params[this.paramNames.query]);
			}
			if (fields.length)
			{
				store.proxy.extraParams[this.paramNames.fields] = Ext
						.encode(fields);
				store.proxy.extraParams[this.paramNames.query] = val;
			}

			// reload store
			store.load();
		}

	} // eo function onTriggerSearch

	/**
	 * @param {Boolean}
	 *            true to disable search (TwinTriggerField), false to enable
	 */
	,
	setDisabled			: function()
	{
		this.m_obj_Field.setDisabled.apply(this.m_obj_Field, arguments);
	} // eo function setDisabled
	// }}}
	// {{{
	/**
	 * Enable search (TwinTriggerField)
	 */
	,
	enable				: function()
	{
		this.setDisabled(false);
	} // eo function enable
	// }}}
	// {{{
	/**
	 * Enable search (TwinTriggerField)
	 */
	,
	disable				: function()
	{
		this.setDisabled(true);
	} // eo function disable
	// }}}
	// {{{
	/**
	 * private (re)configures the plugin, creates menu items from column model
	 */
	,
	reconfigure			: function()
	{
		// remove old items
		var menu = this.menu;
		menu.removeAll();

		// add Select All item plus separator
		if (this.showSelectAll && 'radio' !== this.menuStyle)
		{
			menu.add(Ext.create('Ext.menu.CheckItem',
							{
								text		: this.selectAllText,
								checked		: (this.checkIndexes instanceof Array),
								hideOnClick	: false,
								handler		: function(item)
								{
									var checked = !item.checked;
									item.parentMenu.items.each(function(i)
											{
												if (item !== i && i.setChecked
														&& !i.disabled)
												{
													i.setChecked(checked);
												}
											});
								}
							}
					), '-'
			);
		}
		// add new items
		var obj_Columns = this.m_obj_Grid.columns;
		var group = undefined;
		if ('radio' === this.menuStyle)
		{
			group = 'g' + (new Date).getTime();
		}
		Ext.each(this.m_obj_Grid.columns, function(obj_Column, int_Index,
				arr_Array)
		{
			var disable = false;
			if (obj_Column.text && obj_Column.dataIndex)
			{
				Ext.each(this.disableIndexes, function(item)
				{
					disable = disable ? disable : item === obj_Column.dataIndex;
				}
				);
				if (!disable)
				{
					menu.add(Ext.create('Ext.menu.CheckItem',
							{
								text		: obj_Column.text,
								hideOnClick	: false,
								group		: group,
								checked		: 'all' === this.checkIndexes,
								dataIndex	: obj_Column.dataIndex
							}));
				}
			}
		}, this
		);
		// check items
		if (this.checkIndexes instanceof Array)
		{
			Ext.each(this.checkIndexes, function(di)
					{
						var item = menu.items.find(function(itm)
								{
									return itm.dataIndex === di;
								});
						if (item)
						{
							item.setChecked(true, true);
						}
					}, this);
		}
		// disable items
		if (this.readonlyIndexes instanceof Array)
		{
			Ext.each(this.readonlyIndexes, function(di)
					{
						var item = menu.items.find(function(itm)
								{
									return itm.dataIndex === di;
								});
						if (item)
						{
							item.disable();
						}
					}, this);
		}
		// }}}

	} // eo function reconfigure

}
);
